#ifndef CH_LISTCTRL_H
#define CH_LISTCTRL_H

#pragma once

#include "CHFlatHeaderCtrl.h"
#include "CHSortClass.h"

/////////////////////////////////////////////////////////////////////////////
// CHListCtrlBase is a class which implements a the extended list control
// services provided by the Xtreme Toolkit list control classes
//

class AFX_EXT_CLASS CHListCtrlBase
{
//    DECLARE_DYNAMIC(CHListCtrlBase)

public:

    // Constructs a CHListCtrlBase object.
    //
    CHListCtrlBase();

    // Destroys a CHListCtrlBase object, handles cleanup and de-allocation.
    //
    virtual ~CHListCtrlBase();

    BOOL              m_bAutoFont;    // if TRUE the font will automatically be set for the control.

protected:

    class CListCtrl_Friendly : public CListCtrl
    {
        friend class CHListCtrlBase; // needed in order to access protected fn's
    };

    void ImplAttach(CListCtrl *pListCtrl);

    CListCtrl_Friendly *m_pListCtrl;

    int               m_nMinColWidth; // minimum width for columns
    int               m_nMaxColWidth; // maximum width for columns
    int               m_nSortedCol;   // index of currently selected column
    CHFlatHeaderCtrl m_flatHeader;   // subclassed flat header control.
    CString           m_strSection;   // registry section name.
    CString           m_strEntry;     // registry entry name.
    CString           m_strDefault;   // registry default value.
    COLORREF          m_clrText;      // RGB value for row text color.
    COLORREF          m_clrTextBk;    // RGB value for row text background color.
    bool              m_bNoColSizing; // if true, column sizing is disabled.
    bool              m_bAscending;   // flag to determine sorting order
    bool              m_bAutoSave;    // true if saving column widths.

public:

    // Call this member function to get a pointer to the flat header control.
    // Returns A pointer to a CHFlatHeaderCtrl if subclassed, otherwise NULL.
    //
    CHFlatHeaderCtrl* GetFlatHeaderCtrl();

    // This member function will set the sort image for the
    // specified column.
    // Returns the zero-based index of the previously sorted column.
    virtual int SetSortImage(
        // Zero-based index of the column to set the sort image for.
        int nCol,
        // TRUE if ascending, otherwise FALSE.
        BOOL bAsc);

    // This member function will return the column width stored
    // in the registry.
    //
    virtual int GetStoredWidth(
        // Zero-based index of the column.
        int nCol);

    // This member function will set the column width from the 
    // registry settings.
    //
    virtual void SetStoredWidth(
        // Zero-based index of the column.
        int nCol);

    // This member function loads column widths from the registry.
    //
    virtual void LoadColumnWidths();

    // This member function saves column widths to the registry.
    //
    virtual void SaveColumnWidths();

    // This member function will automatically size a given column. Pass in a -1 to
    // auto fit all columns.
    //
    virtual void AutoSizeColumn(
        // Zero-based index of the column.
        int nCol=-1);

    // This member function will initialize the autosave feature. If 
    // called column widths will be saved to system registry when the 
    // list control window is destroyed.
    //
    virtual void AutoSaveColumns(
        // Registry section name, if NULL the default is "Settings".
        LPCTSTR lpszSection=NULL,
        // Registry entry name, if NULL the default is "Column Info".
        LPCTSTR lpszEntry=NULL,
        // Registry default value, if NULL the default id.
        LPCTSTR lpszDefault=NULL);

    // Call this member function to subclass the the flat header control.
    //
    virtual bool SubclassHeader(
        // true to use a bold font in the header control
        bool bBoldFont=false);

    // Override this member function in your derived class to peform 
    // custom sort routines.
    //
    virtual bool SortList(
        // passed in from control, index of column clicked.
        int nCol,
        // passed in from control, true if sort order should 
        // be ascending.
        bool bAscending );

    // This member function is called to set extended styles for the 
    // list control ie: LVS_EX_FULLROWSELECT, LVS_EX_GRIDLINES, etc.
    virtual void SetExtendedStyle(
        // Specifies the LVS_EX_ style to set.
        DWORD dwExStyle );

    // This member function is called to return the list control 
    // extended style.
    virtual DWORD GetExtendedStyle();

    // Call this member function to enable/disable column sizing
    //
    virtual void DisableColumnSizing(
        // true to disable column sizing, false to enable.
        bool bDisable);

    // Call this member function to set a minimum column size
    //
    void SetMinimumColSize(
        // Size in pixels of the column minimum size.
        int nSize);

	// Call this member function to get the minimum column size for
	// the list control.
	//
	int GetMinimumColSize();

	// Call this member function to get the maximum column size for
	// the list control.
	//
	int GetMaximumColSize();

    // Call this member function to determine the row index and 
    // column index for a point.
    // Returns the row index or -1 if point is not over a row.
    //
    virtual int HitTestEx(
        // point to be tested.
        CPoint &point,
        // address of the column index
        int *col) const;

    // Adds column after the right most column.
    // Returns the index of the new column if successful or -1 otherwise.
    //
    virtual int AddColumn(
        // The column's heading
        LPCTSTR lpszColHeading,
        // Width of the column, in pixels. If this 
        // parameter is -1, the column width is the 
        // same as previous column
        int nWidth = -1,
        // The alignment of the column. Can be LVCFMT_LEFT,
        // LVCFMT_RIGHT, or LVCFMT_CENTER.
        int nFormat=LVCFMT_LEFT);
    
    // This member function will build the columns for the list control. 
    // Returns false if an error occured.
    //
    virtual bool BuildColumns(
        // number of columns the list control contains
        int nCols,
        // int array containing the column widths
        int* nWidth,
        // CString array containing the string for each column
        CString* strColString );
    
    // This member function will build the columns for the list control.
    // Returns false if an error occured.
    //
    virtual bool BuildColumns(
        // number of columns the list control contains
        int nCols,
        // int array containing the column widths
        int* nWidth,
        // int array containing the  string resource id 
        // for each column
        int* nColString );

    // Sets the row text and background colors.
    //
    virtual void SetRowColors(
        // RGB value for the row text
        COLORREF clrText,
        // RGB value for the row background
        COLORREF clrTextBk);
    
    // Returns the number of columns in the list.
    //
    virtual int GetColumnCount();

    // Copies a row to a new location.
    //
    virtual bool CopyRow(
        // Index of the source row
        int nFrom,
        // Index of the destination row
        int nTo);

    // Moves a row to a new location.
    //
    virtual bool MoveRow(
        // Index of the source row
        int nFrom,
        // Index of the destination row
        int nTo);

    // utility function to retrieve the associated header control
    CHeaderCtrl *XGetHeaderCtrl() const;

//:Ignore
#if _MSC_VER < 1200 // MFC 5.0
	POSITION GetFirstSelectedItemPosition() const;
	int GetNextSelectedItem(POSITION& pos) const;
#endif // MFC 5.0
//:End Ignore

protected:

//:Ignore
    // message implementation
    virtual BOOL OnNotifyImpl(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
    virtual void PreSubclassWindowImpl_Post();
    afx_msg void OnCustomDrawImpl(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDestroyImpl_Pre();
    afx_msg BOOL OnEraseBkgndImpl(CDC* pDC);
    afx_msg void OnPaintImpl();
    afx_msg int OnCreateImpl_Post(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnSettingChangeImpl_Post(UINT uFlags, LPCTSTR lpszSection);
//:End Ignore
};

/////////////////////////////////////////////////////////////////////////////
// CHListCtrl is a CListCtrl derived class which implements a
// flat header and generic sorting routines.  See CHListCtrlBase for additional
// functionality.
//
class AFX_EXT_CLASS CHListCtrl : public CListCtrl, public CHListCtrlBase
{
    DECLARE_DYNAMIC(CHListCtrl)

public:
    
    // Constructs a CHListCtrl object.
    //
    CHListCtrl();

    // Destroys a CHListCtrl object, handles cleanup and de-allocation.
    //
    virtual ~CHListCtrl();

    // This member function is called to set extended styles for the 
    // list control ie: LVS_EX_FULLROWSELECT, LVS_EX_GRIDLINES, etc.
    virtual void SetExtendedStyle(
        // Specifies the LVS_EX_ style to set.
        DWORD dwExStyle );

    // This member function is called to return the list control 
    // extended style.
    DWORD GetExtendedStyle();

protected:
	bool m_bInitControl;    // true for initialization.
	
    //:Ignore
    //{{AFX_VIRTUAL(CHListCtrl)
    protected:
    virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
    virtual void PreSubclassWindow();
    //}}AFX_VIRTUAL
    //:End Ignore

    //:Ignore
    //{{AFX_MSG(CHListCtrl)
    afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnDestroy();
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnPaint();
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection);
    //}}AFX_MSG
	afx_msg LRESULT OnInitControl(WPARAM wParam, LPARAM lParam);
    //:End Ignore

    DECLARE_MESSAGE_MAP()
};

//////////////////////////////////////////////////////////////////////////////

AFX_INLINE DWORD CHListCtrl::GetExtendedStyle() {
	return CHListCtrlBase::GetExtendedStyle();
}
AFX_INLINE void CHListCtrl::SetExtendedStyle(DWORD dwExStyle){
	CHListCtrlBase::SetExtendedStyle(dwExStyle);
}

/////////////////////////////////////////////////////////////////////////////


AFX_INLINE DWORD CHListCtrlBase::GetExtendedStyle() {
    ASSERT(::IsWindow(m_pListCtrl->GetSafeHwnd())); return (DWORD)m_pListCtrl->SendMessage(LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
}
AFX_INLINE void CHListCtrlBase::SetExtendedStyle(DWORD dwExStyle) {
    ASSERT(::IsWindow(m_pListCtrl->GetSafeHwnd())); m_pListCtrl->SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, GetExtendedStyle()|dwExStyle);
}
AFX_INLINE int CHListCtrlBase::SetSortImage( int nCol, BOOL bAsc ) {
    ASSERT(::IsWindow(m_pListCtrl->GetSafeHwnd())); return m_flatHeader.SetSortImage(nCol, bAsc);
} 
AFX_INLINE void CHListCtrlBase::SetRowColors(COLORREF clrText, COLORREF clrTextBk) {
    m_clrText = clrText; m_clrTextBk = clrTextBk; m_pListCtrl->Invalidate();
}
AFX_INLINE void CHListCtrlBase::SetMinimumColSize(int nSize) {
    m_nMinColWidth = nSize;
}
AFX_INLINE int CHListCtrlBase::GetMinimumColSize() {
	return m_nMinColWidth;
}
AFX_INLINE int CHListCtrlBase::GetMaximumColSize() {
	return m_nMaxColWidth;
}
AFX_INLINE void CHListCtrlBase::DisableColumnSizing(bool bDisable) {
    m_bNoColSizing = bDisable;
}
AFX_INLINE CHFlatHeaderCtrl* CHListCtrlBase::GetFlatHeaderCtrl() {
	ASSERT_VALID(&m_flatHeader);
    return &m_flatHeader;
}
AFX_INLINE CHeaderCtrl* CHListCtrlBase::XGetHeaderCtrl() const 
{
	CHeaderCtrl * const pHeaderCtrl = 
        (CHeaderCtrl*)m_pListCtrl->GetDlgItem(0);

    // If the following assertion fails, you are performing an operation that
	// requires columns to be added, before you added columns.
    // For example, if you called SubclassHeader(), you need to make sure
    // that the call to SubClassHeader() is placed after calls to 
    // InsertColumn().
    ASSERT(pHeaderCtrl != NULL);
	return pHeaderCtrl;
}

//:Ignore
#if _MSC_VER < 1200 // MFC 5.0
AFX_INLINE POSITION CHListCtrlBase::GetFirstSelectedItemPosition() const {
	ASSERT(::IsWindow(m_pListCtrl->GetSafeHwnd())); return (POSITION) (1+m_pListCtrl->GetNextItem(-1, LVIS_SELECTED));
}
AFX_INLINE int CHListCtrlBase::GetNextSelectedItem(POSITION& pos) const {
	ASSERT(::IsWindow(m_pListCtrl->GetSafeHwnd())); int nOldPos = (int)pos-1; pos = (POSITION) (1+m_pListCtrl->GetNextItem(nOldPos, LVIS_SELECTED)); return nOldPos;
}
#endif // MFC 5.0
//:End Ignore

#endif //CH_LISTCTRL_H
